/*
 * DevicesIIC.c
 *
 *      Author: Honrun
 */
#include "gd32f30x.h"
#include "stdio.h"
#include "DevicesDelay.h"
#include "DevicesIIC.h"


#define IIC_SPEED_VALUE     100000
#define IIC_DELAY_TIME      ((1000000.0f / IIC_SPEED_VALUE) + 1.0f)

static void vDMASetAddrAndLenthStart(uint32_t dma_periph, dma_channel_enum channelx, int8_t cDirection, uint32_t uiSourceAddress, uint32_t uiTargetAddress, uint32_t uiLength);


void vIIC0DmaInit(void)
{
    dma_parameter_struct dma_init_struct = {0};

    /* enable DMA0 */
    rcu_periph_clock_enable(RCU_DMA0);

    dma_deinit(DMA0, DMA_CH5);
    dma_struct_para_init(&dma_init_struct);
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr = 0;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = 0;
    dma_init_struct.periph_addr = ((uint32_t)&I2C_DATA(I2C0));
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_LOW;
    dma_init(DMA0, DMA_CH5, &dma_init_struct);
    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH5);
    /* disable DMA channel */
    dma_channel_disable(DMA0, DMA_CH5);

    dma_deinit(DMA0, DMA_CH6);
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.periph_addr = ((uint32_t)&I2C_DATA(I2C0));
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA0, DMA_CH6, &dma_init_struct);
    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH6);
    /* disable DMA channel */
    dma_channel_disable(DMA0, DMA_CH6);

    /* enable I2CX DMA */
    i2c_dma_config(I2C0, I2C_DMA_ON);
}

void vIIC0Init(void)
{
    /* enable GPIOB clock */
    rcu_periph_clock_enable(RCU_GPIOB);
    /* enable I2C0 clock */
    rcu_periph_clock_enable(RCU_I2C0);
    gpio_pin_remap_config(GPIO_I2C0_REMAP, ENABLE);

    gpio_bit_set(GPIOB, GPIO_PIN_8 | GPIO_PIN_9);
    gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_8 | GPIO_PIN_9);

    i2c_deinit(I2C0);
    /* cofigure I2C clock */
    i2c_clock_config(I2C0, IIC_SPEED_VALUE, I2C_DTCY_16_9);
    /* cofigure I2C address */
    i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0);

    /* enable I2C0 */
    i2c_enable(I2C0);
}

/*!
    \brief      reset i2c bus
    \param[in]  none
    \param[out] none
    \retval     none
*/
void vIIC0DeInit(void)
{
    int8_t i = 0;

    gpio_bit_set(GPIOB, GPIO_PIN_8 | GPIO_PIN_9);
    gpio_init(GPIOB, GPIO_MODE_OUT_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_8 | GPIO_PIN_9);

    vDelayUs(100);

    /* 发送9个时钟脉冲，以解除死锁 */
    for(i = 0; i < 9; ++i)
    {
        vDelayUs(5);
        gpio_bit_reset(GPIOB, GPIO_PIN_8);
        vDelayUs(5);
        gpio_bit_reset(GPIOB, GPIO_PIN_9);
        vDelayUs(5);
        gpio_bit_set(GPIOB, GPIO_PIN_8);
        vDelayUs(5);
        gpio_bit_set(GPIOB, GPIO_PIN_9);
    }

    vIIC0Init();
}

/*!
    \brief      reset i2c bus
    \param[in]  none
    \param[out] none
    \retval     none
*/
void vIIC1DeInit(void)
{
}

int8_t cI2CxWriteDatas(uint32_t i2c_periph, uint16_t usIDAddr, uint16_t usRegAddr, void* pvDatas, int32_t iLength)
{
    void (*vI2CxBusReset)(void) = vIIC0DeInit;
    uint8_t *pucDatas = pvDatas;
    uint32_t timeout = 0, startCnt = 0;

    if((iLength < 1) || (pvDatas == NULL))
        return -1;

    vI2CxBusReset = (i2c_periph == I2C0) ? vIIC0DeInit : vIIC1DeInit;

    /* i2c master sends start signal only when the bus is idle */
    for(timeout = 0; (timeout <= I2C_BUSY_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY) != RESET); ++timeout)
    {
        if(timeout >= I2C_BUSY_TIME_OUT)
        {
            vI2CxBusReset();
//            printf("cI2C %08X busy.\r\n", i2c_periph);
            return -2;
        }

        vDelayUs(IIC_DELAY_TIME);
    }

    /* 重试 N 次 */
    for(startCnt = 0; startCnt <= I2C_START_OUT; ++startCnt)
    {
        if(startCnt >= I2C_START_OUT)
        {
            vI2CxBusReset();
//            printf("cI2C %08X start out.\r\n", i2c_periph);
            return -3;
        }

        i2c_start_on_bus(i2c_periph);
        for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND) == RESET); ++timeout)
            vDelayUs(IIC_DELAY_TIME);

        /* send driver address */
        i2c_master_addressing(i2c_periph, usIDAddr, I2C_TRANSMITTER);
        for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND) == RESET); ++timeout)
            vDelayUs(IIC_DELAY_TIME);

        if(timeout < I2C_BYTE_WRITE_TIME_OUT)
            break;

        vDelayUs(100.0f);
    }

    /* 执行后续操作前，必须清除此状态位 */
    i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND);

    /* send reg address */
    i2c_data_transmit(i2c_periph, usRegAddr);

    while((iLength--) > 0)
    {
        /* wait until the transmit data buffer is empty */
        for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_TBE) == RESET); ++timeout)
            vDelayUs(IIC_DELAY_TIME);

        /* send data */
        i2c_data_transmit(i2c_periph, *pucDatas++);
    }

    /* wait until the byte transmission finishes */
    for(timeout = 0; (timeout < (I2C_BYTE_WRITE_TIME_OUT * 2)) && (i2c_flag_get(i2c_periph, I2C_FLAG_BTC) == RESET); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(i2c_periph);
    for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && ((I2C_CTL0(i2c_periph) & I2C_CTL0_STOP) == RESET); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    return 0;
}

int8_t cI2CxReadDatas(uint32_t i2c_periph, uint16_t usIDAddr, uint16_t usRegAddr, void* pvDatas, int32_t iLength)
{
    void (*vI2CxBusReset)(void) = vIIC0DeInit;
    uint8_t *pucDatas = pvDatas;
    uint32_t timeout = 0, startCnt = 0;

    if((iLength < 1) || (pvDatas == NULL))
        return -1;

    vI2CxBusReset = (i2c_periph == I2C0) ? vIIC0DeInit : vIIC1DeInit;

    /* i2c master sends start signal only when the bus is idle */
    for(timeout = 0; (timeout <= I2C_BUSY_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY) != RESET); ++timeout)
    {
        if(timeout >= I2C_BUSY_TIME_OUT)
        {
            vI2CxBusReset();
//            printf("cI2C %08X busy.\r\n", i2c_periph);
            return -2;
        }

        vDelayUs(IIC_DELAY_TIME);
    }

    /* 重试 N 次 */
    for(startCnt = 0; startCnt <= I2C_START_OUT; ++startCnt)
    {
        if(startCnt >= I2C_START_OUT)
        {
            vI2CxBusReset();
//            printf("cI2C %08X start out.\r\n", i2c_periph);
            return -3;
        }

        i2c_start_on_bus(i2c_periph);
        for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND) == RESET); ++timeout)
            vDelayUs(IIC_DELAY_TIME);

        /* send driver address */
        i2c_master_addressing(i2c_periph, usIDAddr, I2C_TRANSMITTER);
        for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND) == RESET); ++timeout)
            vDelayUs(IIC_DELAY_TIME);

        if(timeout < I2C_BYTE_WRITE_TIME_OUT)
            break;

        vDelayUs(100.0f);
    }

    /* 执行后续操作前，必须清除此状态位 */
    i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND);

    /* send reg address */
    i2c_data_transmit(i2c_periph, usRegAddr);
    for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_BTC) == RESET); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    /* 用户手册：必须在START置1前设定 */
    i2c_ackpos_config(i2c_periph, (iLength == 2) ? I2C_ACKPOS_NEXT : I2C_ACKPOS_CURRENT);

    i2c_start_on_bus(i2c_periph);
    for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND) == RESET); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    /* send driver address */
    i2c_master_addressing(i2c_periph, usIDAddr, I2C_RECEIVER);
    for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND) == RESET); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    /* 如果小于3字节，就需要在清除 I2C_FLAG_ADDSEND 前就设置为NAK */
    i2c_ack_config(i2c_periph, (iLength < 3) ? I2C_ACK_DISABLE : I2C_ACK_ENABLE);

    /* 清除此bit后，就会立即启动IIC移位寄存器进行数据读取 */
    i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND);

    while((--iLength) > 0)
    {
        /* 等待 BTC bit 置位，以阻止 IIC 在准确设置 ACK/NACK 状态前进行移位 */
        for(timeout = 0; (timeout < (I2C_BYTE_READ_TIME_OUT * 2)) && (i2c_flag_get(i2c_periph, I2C_FLAG_BTC) == RESET); ++timeout)
            vDelayUs(IIC_DELAY_TIME);

        i2c_ack_config(i2c_periph, (iLength < 3) ? I2C_ACK_DISABLE : I2C_ACK_ENABLE);

        /* read data */
        *pucDatas++ = i2c_data_receive(i2c_periph);
    }

    /* wait until RBNE bit is set */
    for(timeout = 0; (timeout < I2C_BYTE_READ_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_RBNE) == RESET); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    /* read data */
    *pucDatas++ = i2c_data_receive(i2c_periph);

    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(i2c_periph);
    for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (I2C_CTL0(i2c_periph) & I2C_CTL0_STOP); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    return 0;
}

int8_t cI2CxDmaWriteDatas(uint32_t i2c_periph, uint16_t usIDAddr, uint16_t usRegAddr, void* pvDatas, int32_t iLength)
{
    void (*vI2CxBusReset)(void) = vIIC0DeInit;
    dma_channel_enum enumChannelx = DMA_CH5;
    uint32_t dma_periph, timeout = 0, startCnt = 0;

    if((iLength < 1) || (pvDatas == NULL))
        return -1;

    switch(i2c_periph)
    {
        case I2C0: dma_periph = DMA0; enumChannelx = DMA_CH5; break;
        case I2C1: dma_periph = DMA0; enumChannelx = DMA_CH3; break;

        default : return 1;
    }

    vI2CxBusReset = (i2c_periph == I2C0) ? vIIC0DeInit : vIIC1DeInit;

    /* i2c master sends start signal only when the bus is idle */
    for(timeout = 0; (timeout <= I2C_BUSY_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY) != RESET); ++timeout)
    {
        if(timeout >= I2C_BUSY_TIME_OUT)
        {
            vI2CxBusReset();
//            printf("cI2C %08X busy.\r\n", i2c_periph);
            return -2;
        }

        vDelayUs(IIC_DELAY_TIME);
    }

    /* 重试 N 次 */
    for(startCnt = 0; startCnt <= I2C_START_OUT; ++startCnt)
    {
        if(startCnt >= I2C_START_OUT)
        {
            vI2CxBusReset();
//            printf("cI2C %08X start out.\r\n", i2c_periph);
            return -3;
        }

        i2c_start_on_bus(i2c_periph);
        for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND) == RESET); ++timeout)
            vDelayUs(IIC_DELAY_TIME);

        /* send driver address */
        i2c_master_addressing(i2c_periph, usIDAddr, I2C_TRANSMITTER);
        for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND) == RESET); ++timeout)
            vDelayUs(IIC_DELAY_TIME);

        if(timeout < I2C_BYTE_WRITE_TIME_OUT)
            break;

        vDelayUs(100.0f);
    }

    /* 执行后续操作前，必须清除此状态位 */
    i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND);

    /* send reg address */
    i2c_data_transmit(i2c_periph, usRegAddr);
    for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_BTC) == RESET); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    /* 设置传输地址与长度，并启动DMA发送 */
    vDMASetAddrAndLenthStart(dma_periph, enumChannelx, DMA_MEMORY_TO_PERIPHERAL, (uint32_t)pvDatas, (uint32_t)(&I2C_DATA(i2c_periph)), iLength);

    /* 在此放大20倍，是为了在以下超时检测时，减少延时周期，以能够在满足条件时快速退出等待 */
    iLength *= 20;

    /* 等待本次DMA传输完成 */
    while((dma_flag_get(dma_periph, enumChannelx, DMA_FLAG_FTF) == RESET) &&
          ((DMA_CHCTL(dma_periph, enumChannelx) & DMA_CHXCTL_CHEN) != 0)  &&
           (DMA_CHCNT(dma_periph, enumChannelx) != 0)                     &&
          ((iLength--) > 0))
    {
        /* 以10k波特率计算时长（1Byte + 1bit ACK/NACK = 9bit；除以20，是因为上面放大了20倍） */
        vDelayUs(IIC_DELAY_TIME * 9.0f / 20.0f + 1.0f);
    }

    /* wait until the byte transmission finishes */
    for(timeout = 0; (timeout < (I2C_BYTE_WRITE_TIME_OUT * 2)) && (i2c_flag_get(i2c_periph, I2C_FLAG_BTC) == RESET); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(i2c_periph);
    for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && ((I2C_CTL0(i2c_periph) & I2C_CTL0_STOP) == RESET); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    return 0;
}

int8_t cI2CxDmaReadDatas(uint32_t i2c_periph, uint16_t usIDAddr, uint16_t usRegAddr, void* pvDatas, int32_t iLength)
{
    void (*vI2CxBusReset)(void) = vIIC0DeInit;
    uint8_t *pucDatas = pvDatas;
    dma_channel_enum enumChannelx = DMA_CH6;
    uint32_t dma_periph, timeout = 0, startCnt = 0;

    if((iLength < 1) || (pvDatas == NULL))
        return -1;

    switch(i2c_periph)
    {
        case I2C0: dma_periph = DMA0; enumChannelx = DMA_CH6; break;
        case I2C1: dma_periph = DMA0; enumChannelx = DMA_CH4; break;

        default : return 1;
    }

    vI2CxBusReset = (i2c_periph == I2C0) ? vIIC0DeInit : vIIC1DeInit;

    /* i2c master sends start signal only when the bus is idle */
    for(timeout = 0; (timeout <= I2C_BUSY_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY) != RESET); ++timeout)
    {
        if(timeout >= I2C_BUSY_TIME_OUT)
        {
            vI2CxBusReset();
//            printf("cI2C %08X busy.\r\n", i2c_periph);
            return -2;
        }

        vDelayUs(IIC_DELAY_TIME);
    }

    /* 重试 N 次 */
    for(startCnt = 0; startCnt <= I2C_START_OUT; ++startCnt)
    {
        if(startCnt >= I2C_START_OUT)
        {
            vI2CxBusReset();
//            printf("cI2C %08X start out.\r\n", i2c_periph);
            return -3;
        }

        i2c_start_on_bus(i2c_periph);
        for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND) == RESET); ++timeout)
            vDelayUs(IIC_DELAY_TIME);

        /* send driver address */
        i2c_master_addressing(i2c_periph, usIDAddr, I2C_TRANSMITTER);
        for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND) == RESET); ++timeout)
            vDelayUs(IIC_DELAY_TIME);

        if(timeout < I2C_BYTE_WRITE_TIME_OUT)
            break;

        vDelayUs(100.0f);
    }

    i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND);

    /* send reg address */
    i2c_data_transmit(i2c_periph, usRegAddr);
    for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_BTC) == RESET); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    /* 用户手册：必须在START置1前设定 */
    i2c_ackpos_config(i2c_periph, I2C_ACKPOS_CURRENT);

    i2c_start_on_bus(i2c_periph);
    for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND) == RESET); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    /* send driver address */
    i2c_master_addressing(i2c_periph, usIDAddr, I2C_RECEIVER);
    for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND) == RESET); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    /* 如果等于1字节，就需要在清除 I2C_FLAG_ADDSEND 前就设置为NAK */
    i2c_ack_config(i2c_periph, (iLength == 1) ? I2C_ACK_DISABLE : I2C_ACK_ENABLE);

    /* 设置DMA传输结束后，发送NACK */
    i2c_dma_last_transfer_config(i2c_periph, I2C_DMALST_ON);

    /* 设置传输地址与长度，并启动DMA发送 */
    vDMASetAddrAndLenthStart(dma_periph, enumChannelx, DMA_PERIPHERAL_TO_MEMORY, (uint32_t)pvDatas, (uint32_t)(&I2C_DATA(i2c_periph)), iLength);

    /* 清除此bit后，就会立即启动IIC移位寄存器进行数据读取 */
    i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND);

    /* 在此放大20倍，是为了在以下超时检测时，减少延时周期，以能够在满足条件时快速退出等待 */
    iLength *= 20;

    /* 等待本次DMA传输完成 */
    while((dma_flag_get(dma_periph, enumChannelx, DMA_FLAG_FTF) == RESET) &&
          ((DMA_CHCTL(dma_periph, enumChannelx) & DMA_CHXCTL_CHEN) != 0)  &&
           (DMA_CHCNT(dma_periph, enumChannelx) != 0)                     &&
          ((iLength--) > 0))
    {
        /* 以10k波特率计算时长（1Byte + 1bit ACK/NACK = 9bit；除以20，是因为上面放大了20倍） */
        vDelayUs(IIC_DELAY_TIME * 9.0f / 20.0f + 1.0f);
    }

    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(i2c_periph);
    for(timeout = 0; (timeout < I2C_BYTE_WRITE_TIME_OUT) && (I2C_CTL0(i2c_periph) & I2C_CTL0_STOP); ++timeout)
        vDelayUs(IIC_DELAY_TIME);

    return 0;
}

/**
 * @brief  设置DMA的数据传输长度，并启动DMA传输
 * @param  DMAy_Channelx：   相应DMA的通道
           Length：          传输长度
 * @retval 无
 */
static void vDMASetAddrAndLenthStart(uint32_t dma_periph, dma_channel_enum channelx, int8_t cDirection, uint32_t uiSourceAddress, uint32_t uiTargetAddress, uint32_t uiLength)
{
    uint32_t uiTime;

    uiTime = 1000000;
    /* Disable the peripheral */
    dma_channel_disable(dma_periph, channelx);
    while(((DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_CHEN) != 0) && (--uiTime));

    /* 必须要清除所有中断状态，才允许使能DMA */
    dma_interrupt_flag_clear(dma_periph, channelx, DMA_INT_FLAG_G | DMA_INT_ERR | DMA_INT_HTF | DMA_INT_FTF);

    /* configure memory base address */
    dma_memory_address_config(dma_periph, channelx, uiSourceAddress);

    /* configure peripheral base address */
    dma_periph_address_config(dma_periph, channelx, uiTargetAddress);

    /* Configure DMA Stream data length */
    dma_transfer_number_config(dma_periph, channelx, uiLength);

    /* configure the direction of data transfer on the channel   */
    dma_transfer_direction_config(dma_periph, channelx, cDirection);

    uiTime = 1000000;
    /* Enable the Peripheral */
    dma_channel_enable(dma_periph, channelx);
    while(((DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_CHEN) == 0) && (--uiTime));
}
